from flask import current_app
from flask import g, redirect
from flask import request
from flask import session

from info import constants, db
from info.models import Category, News, User
from info.utils.common import user_login_data
from info.utils.image_storage import image_storage
from info.utils.response_code import RET
from . import user_blue
from flask import render_template, jsonify


# 获取其他用户的新闻列表
# 请求路径：/user/other_news_list
# 请求方式：GET
# 请求参数：p,user_id
# 返回值:errno,errmsg
@user_blue.route('/other_news_list')
def other_news_list():
    """
    功能描述：获取其他用户的新闻列表
    思路分析：
        １．获取参数
        ２．校验参数，参数类型转换
        ３．根据作者编号去窗户作者对象
        ４．判断作者对象是否存在
        ５．分页查询作者发布的新闻
        ６．获取分页查询的对象，总页数，当前页数，当前页数对象
        ７．返回响应，携带数据
    :return:
    """
    # １．获取参数
    page = request.args.get('p')
    user_id = request.args.get('user_id')
    # ２．校验参数，参数类型转换
    if not all([page, user_id]):
        return jsonify(errno=RET.NODATA, errmsg="参数错误")

    try:
        page = int(page)
    except Exception as e:
        page = 1
    # ３．根据作者编号去窗户作者对象
    try:
        author = User.query.get(user_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='获取作者失败')

    # ４．判断作者对象是否存在
    if not author:
        return jsonify(errno=RET.DBERR, errmsg='作者不存在')
    # ５．分页查询作者发布的新闻
    try:
        # paginate = News.query.filter(News.id == user_id).order_by(News.create_time.desc()).paginate(page, 3, False)
        paginate = author.news_list.order_by(News.create_time.desc()).paginate(page, 3, False)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='分页查询失败')

    # ６．获取分页查询的对象，总页数，当前页数，当前页数对象
    total_page = paginate.pages
    current_page = paginate.page
    items = paginate.items

    news_list = []
    for news in items:
        news_list.append(news.to_dict())

    # ７．返回响应，携带数据
    data = {
        'total_page': total_page,
        'current_page': current_page,
        'news_list': news_list
    }

    return jsonify(errno=RET.OK, errmsg='获取成功', data=data)


# 获取作者的详情页面
# 请求路径：/user/other
# 请求方式:GET
# 请求参数：id
# 返回值：作者信息
@user_blue.route('/other')
@user_login_data
def other_info():
    """
    功能描述：获取作者的详情页面
    思路分析
        １．获取参数
        ２．校验参数
        ３．通过作者编号获取作者对象
        ４．判断作者是否存在
        ５．携带数据，渲染页面
    :return:
    """
    # １．获取参数
    author_id = request.args.get("id")
    # ２．校验参数
    if not author_id:
        return jsonify(errno=RET.NODATA, errmsg='参数不能为空')
    # ３．通过作者编号获取作者对象
    try:
        author = User.query.get(author_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询失败')

    # ４．判断作者是否存在
    if not author:
        return jsonify(errno=RET.NODATA, errmsg='作者不存在')

    # 判断登陆的用户是否关注过该作者
    is_followed = False
    if g.user:
        if g.user in author.followers:
            is_followed = True

    # ５．携带数据，渲染页面
    data = {
        'author': author.to_dict(),
        'is_followed': is_followed,
        'user_info': g.user.to_dict() if g.user else ''
    }
    return render_template('news/other.html', data=data)


# 获取我的关注
# 请求路径：user/user_follow
# 请求方式:GET
# 请求参数：P
# 返回值：html页面，data字典渲染页面
@user_blue.route('/user_follow')
@user_login_data
def user_follow():
    """
    功能描述:获取用户的关注
    思路分析：
        １．获取参数页数
        ２．参数类型转换
        ３．分页查询我关注的作者
        ４．获取分页查询的对象属性，总页数，当前页数，当前页数对象
        ５．将当前页数对象转成字典
        ６．携带参数渲染页面
    :return:
    """
    # １．获取参数页数
    page = request.args.get('p')
    # ２．参数类型转换
    try:
        page = int(page)
    except Exception as e:
        page = 1
    # ３．分页查询我关注的作者
    try:
        paginate = g.user.followed.paginate(page, 4, False)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='分页查询失败')
    # ４．获取分页查询的对象属性，总页数，当前页数，当前页数对象
    totalPage = paginate.pages
    currentPage = paginate.page
    items = paginate.items
    # ５．将当前页数对象转成字典
    author_list = []
    for author in items:
        author_list.append(author.to_dict())
    # ６．携带参数渲染页面
    data = {
        'totalPage': totalPage,
        'currentPage': currentPage,
        'author_list': author_list
    }
    return render_template('news/user_follow.html', data=data)


# 获取我发布的新闻列表
# 请求路径：user/news_list
# 请求方式：GET
# 请求参数：P
# 返回GET渲染页面
@user_blue.route('/news_list')
@user_login_data
def news_list():
    """
    功能描述：获取我发布的新闻
    思路分析
        １．获取参数页数
        ２．参数类型转换
        ３．分页查询我发布的新闻
        ４．获取分页查询对象属性，总页数，当前页数，当前页数对象
        ５．将当前页数对象转成字典列表
        ６．携带数据渲染页面
    :return:
    """
    # １．获取参数页数
    page = request.args.get('p')
    # ２．参数类型转换
    try:
        page = int(page)
    except Exception as e:
        page = 1
    # ３．分页查询我发布的新闻
    try:
        paginate = News.query.filter(News.user_id == g.user.id).order_by(News.create_time.desc()).paginate(page, 2,
                                                                                                           False)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='分页查询失败')

    # ４．获取分页查询对象属性，总页数，当前页数，当前页数对象
    totalPage = paginate.pages
    currentPage = paginate.page
    items = paginate.items
    # ５．将当前页数对象转成字典列表
    newslist = []
    for news in items:
        newslist.append(news.to_review_dict())
    data = {
        'totalPage': totalPage,
        'currentPage': currentPage,
        'newslist': newslist
    }
    # ６．携带数据渲染页面
    return render_template('news/user_news_list.html', data=data)


# 用户发布新闻
# 请求路径：user/news_release
# 请求方式：GET,POST
# 请求参数：title(新闻标题), category_id(新闻分类),digest(新闻摘要),index_image(新闻图片),content(新闻内容)
# 返回值：GET返回页面数据，POST返回errno,errmsg
@user_blue.route('/news_release', methods=['GET', 'POST'])
@user_login_data
def news_release():
    """
    功能描述：用户新闻发布
    思路分析：
        １．判断请求方式，GET请求返回发布新闻页面
        ２．POST请求发布新闻
        ３．获取参数
        ４．校验参数
        ５．上传图片
        ６．判断图片是否上传成功
        ７．创建新闻对象属性
        ８．保存新闻到数据库
        ９．返回响应
    :return:
    """
    # １．判断请求方式，GET请求返回发布新闻页面
    if request.method == "GET":
        try:
            categoies = Category.query.all()
            categoies.pop(0)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='获取分类信息失败')

        return render_template('news/user_news_release.html', categoies=categoies)
    # ２．POST请求发布新闻
    # ３．获取参数
    title = request.form.get('title')
    category_id = request.form.get('category_id')
    digest = request.form.get('digest')
    content = request.form.get('content')
    index_image = request.files.get('index_image')
    # ４．校验参数
    if not all([title, category_id, digest, content, index_image]):
        return jsonify(errno=RET.DATAERR, errmsg='参数不能为空')
    # ５．上传图片
    try:
        image_name = image_storage(index_image.read())
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg='七牛云上传异常')
    # ６．判断图片是否上传成功
    if not image_name:
        return jsonify(errno=RET.THIRDERR, errmsg='上传图片异常')
    # ７．创建新闻对象属性
    news = News()
    news.title = title
    news.source = g.user.nick_name
    news.digest = digest
    news.content = content
    news.index_image_url = constants.QINIU_DOMIN_PREFIX + image_name
    news.category_id = category_id
    news.user_id = g.user.id
    news.status = 1

    # ８．保存新闻到数据库
    try:
        db.session.add(news)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg='发布新闻失败')
    # ９．返回响应
    return jsonify(errno=RET.OK, errmsg='发布新闻成功')


# 我的收藏
# 请求地址：user/collection
# 请求方式：GET
# 请求参数：P
# 返回值：html页面
@user_blue.route('/collection')
@user_login_data
def collection():
    """
    功能描述：用户收藏列表
    思路分析
        １．获取参数
        ２．参数类型转换
        ３．分页查询
        ４．获取分页对象属性，总页数，当前页，当前页对象
        ５．　将当前页对象转成字典列表
        ６．携带数据，渲染页面
    :return:
    """
    # １．获取参数
    page = request.args.get('p', '1')
    # ２．参数类型转换
    try:
        page = int(page)
    except Exception as e:
        page = 1
    # ３．分页查询
    try:
        paginate = g.user.collection_news.paginate(page, 6, False)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询分页失败')

    # ４．获取分页对象属性，总页数，当前页，当前页对象
    totalPage = paginate.pages
    currentPage = paginate.page
    items = paginate.items
    # ５．　将当前页对象转成字典列表
    news_list = []
    for news in items:
        news_list.append(news.to_dict())
    data = {
        'totalPage': totalPage,
        'currentPage': currentPage,
        'news_list': news_list
    }
    # ６．携带数据，渲染页面
    return render_template('news/user_collection.html', data=data)


# 用户修改密码
# 请求地址：user/pass_info
# 请求方式：post
# 请求参数：old_password（旧密码），new_password(新密码)
# 返回值：errno,errmsg
@user_blue.route('/pass_info', methods=['GET', 'POST'])
@user_login_data
def pass_info():
    """
    功能描述：用户修改密码
    思路分析：
        １．获取参数
        ２．校验参数，非空校验
        ３．校验密码是否正确
        ４．设置密码密码
        ５．返回值
    :return:
    """
    if request.method == 'GET':
        return render_template('news/user_pass_info.html')
    # １．获取参数
    old_password = request.json.get('old_password')
    new_password = request.json.get('new_password')
    # ２．校验参数，非空校验
    if not all([old_password, new_password]):
        return jsonify(errno=RET.DATAERR, errmsg='参数错误')
    # ３．校验密码是否正确
    if not g.user.check_passowrd(old_password):
        return jsonify(errno=RET.DATAERR, errmsg='密码错误')
    try:
        # ４．设置密码密码
        g.user.password = new_password
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='修改密码失败')
    # 修改密码成功自动退出，清除session
    session.pop('user_id')
    session.pop('nick_name')
    session.pop('mobile')
    # ５．返回值
    return jsonify(errno=RET.OK, errmsg='修改密码成功')


# 获取修改用户头像
# 请求地址：user/pic_info
# 请求方式：GET,POST
# 请求参数：post请求参数：avatar
# 返回值：errno, errmsg
@user_blue.route('/pic_info', methods=['GET', 'POST'])
@user_login_data
def pic_info():
    """
    功能描述：修改用户头像
    思路分析：
        １．判断请求方式，GET请求返回用户头像
        ２．POST请求修改用户头像，参数avtar头像图片路径
        ３．获取参数
        ４．校验参数
        ５．调用工具类，上传图片
        ６．判断图片是否上传成功
        ７．修改数据
        ８．返回值
    :return:
    """
    # １．判断请求方式，GET请求返回用户头像
    if request.method == 'GET':
        return render_template('news/user_pic_info.html', user=g.user.to_dict())

    # ２．POST请求修改用户头像，参数avtar头像图片路径
    # ３．获取参数
    avatar = request.files.get('avatar')
    # ４．校验参数
    if not avatar:
        return jsonify(errno=RET.DATAERR, errmsg='参数错误')
    # ５．调用工具类，上传图片
    try:
        image_name = image_storage(avatar.read())
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg='上传七牛云失败')

    # ６．判断图片是否上传成功
    if not image_name:
        return jsonify(errno=RET.THIRDERR, errmsg='上传失败')
    # ７．修改数据
    try:
        g.user.avatar_url = image_name
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='修改失败')

    # ８．返回值，携带图片地址
    data = {
        "avatar_url": constants.QINIU_DOMIN_PREFIX + image_name
    }
    return jsonify(errno=RET.OK, errmsg='修改成功', data=data)


# 获取用户基本资料
# 请求地址：user/base_info
# 请求参数：GEF,POST
# 请求参数：post请求，nick_name(用户名),signature（个性签名）,gender（性别）
# 返回值，errno,errmsg
@user_blue.route('/base_info', methods=['GET', 'POST'])
@user_login_data
def base_info():
    """
    功能描述：显示和修改用户的基本资料
    思路分析
        １．判断用户请求的方式，GET请求显示用户页面
        ２．POST请求修改用户资料，需要参数nick_name(用户名),signature（个性签名）,gender（性别）
        ３．获取参数
        ４．校验参数，非空校验
        ５．修改用户信息
        ６．返回响应
    :return:
    """
    # １．判断用户请求的方式，GET请求显示用户页面
    if request.method == 'GET':
        return render_template('news/user_base_info.html', user=g.user.to_dict())

    # ２．POST请求修改用户资料，需要参数nick_name(用户名), signature（个性签名）, gender（性别）
    # ３．获取参数
    nick_name = request.json.get('nick_name')
    signature = request.json.get('signature')
    gender = request.json.get('gender')
    # ４．校验参数，非空校验
    if not all([nick_name, signature, gender]):
        return jsonify(errno=RET.DATAERR, errmsg='参数不能为空')
    # 性别校验
    if gender not in ['MAN', 'WOMAN']:
        return jsonify(errno=RET.DATAERR, errmsg='性别错误')
    # ５．修改用户信息
    try:
        g.user.nick_name = nick_name
        g.user.signature = signature
        g.user.gender = gender
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='修改信息失败')

    # ６．返回响应
    return jsonify(errno=RET.OK, errmsg='修改成功')


# 显示个人中心页面
# 请求路径：user/info
# 请求方式：GET
# 请求参数：无
# 返回值：页面信息，data数据
@user_blue.route('/info')
@user_login_data
def user_index():
    # 判断用户是否登陆
    if not g.user:
        return redirect('/')

    data = {
        'user_info': g.user.to_dict() if g.user else ''
    }
    return render_template('news/user.html', data=data)
